// CppProject.h

#pragma once
#include "File.h"
#include "..\graphicengine\igraphicengine.h"
#include "..\graphicengine\graphicengine.h"
#include "FEM.h"
#include<string>


using namespace System::Collections::Generic;
using namespace System;
using namespace Windows::Forms;
using namespace System::Drawing;
using namespace System::Runtime::InteropServices;
using namespace Microsoft::Office::Interop::Excel;
// 
 #define Excel  Microsoft::Office::Interop::Excel

namespace CppProject {

	
	ref struct Flag
	{
		double F;
		double DfDx;
		double DfDy;
		double RealX;
		double RealY;
		int	   IntX;
		int	   IntY;
	};


	public ref class CppController
	{
		static const int Version = 0x1;
		List<Flag^> ^Flags;
				

		FEM *Fem;
		IgraphicEngine *Graphic;

		PointF ViewPortCenter;
		double ViewPortDiameter;

		bool _MouseInFlagMode;
		bool FlagsDrawF;
		bool FlagsDrawDfDx;
		bool FlagsDrawDfDy;
		bool DrawFlags;
		bool DrawIsoLines;
		bool DrawFemGrid;
		bool DrawGrade;
		bool DrawAxis;

	private:
		void ErrorHandler(CException &e)
		{
			::MessageBoxW(NULL, e.errorMessage(), L"Initializing error", MB_OK|MB_ICONERROR);
		}

	public:
		void test(int x,int y)
		{
			sIntPoint a(x,y);
			sRealPoint b=Graphic->IntPoint2RealPoint(a);
			a=sIntPoint(0,0);
// 			b.x=-428;
// 			b.y=2*428;
			a=Graphic->RealPoint2IntPoint(b);
			MessageBox::Show(b.x.ToString() + ", " + b.y.ToString() + "\n" + a.x.ToString() + ", " + a.y.ToString());
		}

		CppController():ViewPortDiameter(428)
		{
			Graphic = new TceRisovarius; 			
			try
			{
				Fem = new FEM();
				Fem->SetGraphicObject(Graphic);
				Fem->OpenTask("../CppProject/FemData/inf2tr.txt", "../CppProject/FemData/nvtr.dat", "../CppProject/FemData/rz.dat", "../CppProject/FemData/v2.dat" , "../CppProject/FemData/nvkat2d.dat");		
			}
			catch (CException &e)
			{
				ErrorHandler(e);
			}

			ViewPortCenter.X=0.0;
			ViewPortCenter.Y=0.0;
			Flags = gcnew List<Flag^>;

			_MouseInFlagMode = false;
			FlagsDrawF = true;
			FlagsDrawDfDx = true;
			FlagsDrawDfDy = true;
			DrawFlags = false;
			DrawIsoLines = false;
			DrawGrade=false;
			DrawAxis=false;
		}
		~CppController() 
		{
			delete Graphic;
			delete Fem;
		}


		//------------------------------------------------------------------------------------------------------
		PointF MaxMinValue()
		{
			sRealPoint p = Fem->maxMinValue();		
			return PointF(p.x, p.y);
		}


		//------------------------------------------------------------------------------------------------------
		void OpenTask(String ^iInf2trFile, String ^iGlobalNumberFile, String ^iVertexFile, String ^iSolutionFile, String ^iMaterialsFile)
		{
			char* inf2tr_file = (char*)Marshal::StringToHGlobalAnsi(iInf2trFile).ToPointer();
			char* global_number_file = (char*)Marshal::StringToHGlobalAnsi(iGlobalNumberFile).ToPointer();
			char* vertex_file = (char*)Marshal::StringToHGlobalAnsi(iVertexFile).ToPointer();
			char* solution_file = (char*)Marshal::StringToHGlobalAnsi(iSolutionFile).ToPointer();
			char* materials_file = (char*)Marshal::StringToHGlobalAnsi(iMaterialsFile).ToPointer();

			try
			{
				Fem->OpenTask(inf2tr_file, global_number_file, vertex_file, solution_file, materials_file);
			}
			catch (CException &e)
			{
				ErrorHandler(e);
			}

			Marshal::FreeHGlobal((IntPtr)inf2tr_file);
			Marshal::FreeHGlobal((IntPtr)global_number_file);
			Marshal::FreeHGlobal((IntPtr)vertex_file);
			Marshal::FreeHGlobal((IntPtr)solution_file);
			Marshal::FreeHGlobal((IntPtr)materials_file);
		}

		//------------------------------------------------------------------------------------------------------
		void SetWindow(IntPtr iWindow)
		{
			Graphic->SetWindowForPaint((HWND)iWindow.ToPointer());

			sRealPoint center={ViewPortCenter.X, ViewPortCenter.Y};
			Graphic->SetViewPort(center, ViewPortDiameter);	
			Graphic->SetColor(RGB(255,255,255));

// 			vector<double> isolines;
// 			isolines.push_back(0);
// 			isolines.push_back(100);
// 			Graphic->SetIsolines(isolines);
		}


		//-----------------------------------------------------------------------------------------------------
		void DoPaint()
		{
			Graphic->BeginPaint();
			Fem->draw(DrawFemGrid, DrawGrade, DrawIsoLines, false, DrawAxis);
			if(DrawFlags)
			{
				for(int i=0; i<Flags->Count; i++)
				{
					sTitleInfo stinfo;
					stinfo.color = RGB(230,230,230);
					stinfo.point.x = Flags[i]->RealX;
					stinfo.point.y = Flags[i]->RealY;
					
					stinfo.text[0] = 0;
					if(FlagsDrawF)
						sprintf_s(stinfo.text, 256, "f: %e\n", Flags[i]->F);
					if(FlagsDrawDfDx)
						sprintf_s(stinfo.text, 256, "%sDfDx: %e\n", stinfo.text, Flags[i]->DfDx);
					if(FlagsDrawDfDy)
						sprintf_s(stinfo.text, 256, "%sDfDy: %e", stinfo.text, Flags[i]->DfDy);
					
					

					Graphic->DrawTitle(stinfo);
				}
			}

			Graphic->EndPaint();			
		}

		
		//-----------------------------------------------------------------------------------------------------
		void AddFlag(int iX, int iY)
		{
			Flag ^f = gcnew Flag;
			f->IntX = iX;
			f->IntY = iY;
		
			//to real coords
			sRealPoint rp;
			sIntPoint ip(iX, iY);
			rp = Graphic->IntPoint2RealPoint(ip);

			f->RealX = rp.x;
			f->RealY = rp.y;
			f->F = Fem->value_in_point(rp);
			sRealPoint df = Fem->partial_in_point_dx_dy(rp);
			f->DfDx = df.x;
			f->DfDy = df.y;				 

			Flags->Add(f);
			DoPaint();
		}

		
		//-----------------------------------------------------------------------------------------------------
		void ApplyGraphicsSettings(bool iAxes, bool iGrid, bool iFemGrid, bool iIsoLines, bool iLabels)
		{
			DrawFemGrid	 = iFemGrid;
			DrawFlags = iLabels;
			DrawIsoLines = iIsoLines;
			DrawAxis=iAxes;
			DrawGrade=iGrid;
			DoPaint();
		}


		//------------------------------------------------------------------------------------------------------
		void SetFlagsMode(bool iDrawF, bool iDrawDfDx, bool iDrawDfDy)
		{
			FlagsDrawF = iDrawF;
			FlagsDrawDfDx = iDrawDfDx;
			FlagsDrawDfDy = iDrawDfDy;
			DoPaint();
		}


		//------------------------------------------------------------------------------------------------------
		void ZoomIn()
		{
			//MessageBox::Show("Zoom in");
			ViewPortDiameter /= 2;
			sRealPoint center={ViewPortCenter.X, ViewPortCenter.Y};
			Graphic->SetViewPort(center, ViewPortDiameter);		
			DoPaint();
		}


		//------------------------------------------------------------------------------------------------------
		void ZoomOut()
		{
			ViewPortDiameter *= 2;
			sRealPoint center={ViewPortCenter.X, ViewPortCenter.Y};
			Graphic->SetViewPort(center, ViewPortDiameter);		
			DoPaint();
		}


		//------------------------------------------------------------------------------------------------------
		property bool MouseInFlagMode
		{
			bool get() { return _MouseInFlagMode; }
			void set(bool x) { _MouseInFlagMode = x; }
		}


		//------------------------------------------------------------------------------------------------------
		void MoveViewport(int iNewX, int iNewY, int iOldX, int iOldY)
		{
			//MessageBox::Show("Zoom out");
			
			sRealPoint newRealCenter;
			sIntPoint newIntCenter(iNewX, iNewY);
			newRealCenter=Graphic->IntPoint2RealPoint(newIntCenter);

			sRealPoint oldRealCenter;
			sIntPoint oldIntCenter(iOldX, iOldY);
			oldRealCenter=Graphic->IntPoint2RealPoint(oldIntCenter);

			newRealCenter.x =  ViewPortCenter.X + newRealCenter.x - oldRealCenter.x;
			newRealCenter.y =  ViewPortCenter.Y + newRealCenter.y - oldRealCenter.y;

			ViewPortCenter.X = newRealCenter.x;
			ViewPortCenter.Y = newRealCenter.y;
			
			Graphic->SetViewPort(newRealCenter, ViewPortDiameter);
			DoPaint();
		}

		
		//------------------------------------------------------------------------------------------------------
		void SetColorScale(List<double>^ iFuncs, List<Color> ^Colors)
		{
			vector<double> f;
			vector<COLORREF> c;

			for(int i=0; i<iFuncs->Count; i++)
			{
				f.push_back(iFuncs[i]);
				if(i!=iFuncs->Count-1)
					c.push_back(RGB(Colors[i].R, Colors[i].G, Colors[i].B));
			}
			Graphic->SetColorRange(f, c);
			DoPaint();
 		}


		//------------------------------------------------------------------------------------------------------
		void SetIsoLines(double iMin, double iMax, int iSteps)
		{
			try
			{
				vector<double> isolines;
				//isolines.push_back(iMin);
				//double step = (iMax - iMin)/iSteps;
				//for(int i=1; i<iSteps; i++)
				//{
				//	isolines.push_back(iMin + step*i);
				//}
				//isolines.push_back(iMax);
				/*Graphic->SetIsolines(isolines);*/

				Fem->set_izoline(iMax, iMin, iSteps);
				//Fem->draw(true, false, true, false);
				DoPaint();
			}
			catch (CException &e)
			{
			}			
		}


		//------------------------------------------------------------------------------------------------------
		void ExportToTxt(String ^iFilePath)
		{
			char* file_path = (char*)Marshal::StringToHGlobalAnsi(iFilePath).ToPointer();
			try
			{
				std::ofstream f;
				f.open(file_path);
				f << "x\ty\tf\t\DfDx\tDfDy\n\n";

				for(int i=0; i<Flags->Count; i++)
				{
					f << Flags[i]->RealX << "\t";
					f << Flags[i]->RealY << "\t";
					f << Flags[i]->F << "\t";
					f << Flags[i]->DfDx << "\t";
					f << Flags[i]->DfDy << "\n";
				}
				
				f.close();
			}
			catch (CException &e)
			{
				ErrorHandler(e);
			}
			Marshal::FreeHGlobal((IntPtr)file_path);
		}


		//------------------------------------------------------------------------------------------------------
		void ResizeGraphicWindow(IntPtr iHandle, int iNewW, int iNewH)
		{
			Graphic->SetWindowForPaint((HWND)iHandle.ToPointer());
		}

		//------------------------------------------------------------------------------------------------------
		void ClearFlags()
		{
			Flags->Clear();
			DoPaint();
		}


		//------------------------------------------------------------------------------------------------------
		void SaveToPostProcFile(String ^iFilePath, String ^iColorScaleString, String ^iIsoLineString)
		{
			char* file_path = (char*)Marshal::StringToHGlobalAnsi(iFilePath).ToPointer();
			char* color_scale_string = (char*)Marshal::StringToHGlobalAnsi(iColorScaleString).ToPointer();
			char* isoline_string = (char*)Marshal::StringToHGlobalAnsi(iIsoLineString).ToPointer();

			try
			{
				CFile f;
				f.OpenFile(file_path, AM_WRITE, true);

				//write attributes
				sClassAttributes  ca(CppController::Version, "CppControllerPostProc");
				f.WriteAttributes(ca);


				//write flags
				long count = Flags->Count;
				f << count;

				for(int i=0; i<Flags->Count; i++)
				{
					f << Flags[i]->RealX;
					f << Flags[i]->RealY;
				}
				
				f << color_scale_string;
				f << isoline_string; 

				f.CloseFile();
			}
			catch (CException &e)
			{
				ErrorHandler(e);
			}
			Marshal::FreeHGlobal((IntPtr)file_path);
			Marshal::FreeHGlobal((IntPtr)color_scale_string);
			Marshal::FreeHGlobal((IntPtr)isoline_string);
		}


		//------------------------------------------------------------------------------------------------------
		void LoadFromPostProcFile(String ^iFilePath, String ^%oFileColorScaleString, String ^%oIsoLineString)
		{
			char* file_path = (char*)Marshal::StringToHGlobalAnsi(iFilePath).ToPointer();
			CString color_scale;
			CString isolines;

			try
			{
				CFile f;
				f.OpenFile(file_path, AM_READ, true);

				//read attributes
				sClassAttributes  ca;
				f.ReadAttributes(ca);
				if(ca.ClassName != "CppControllerPostProc" || ca.Version < CppController::Version)
					throw CException(0, "Bad file format");


				//read flags
				long count = 0;
				f >> count;
				for(int i=0; i<count; i++)
				{
					double x = 0;
					double y = 0;
					f >> x;
					f >> y;

					Flag ^flag = gcnew Flag;
					flag->RealX = x;
					flag->RealY = y;

					
					//to int coords
					sRealPoint rp;
					rp.x = x;
					rp.y = y;
					sIntPoint ip;
					ip = Graphic->RealPoint2IntPoint(rp);
					flag->IntX = ip.x;
					flag->IntY = ip.y;

					
					flag->F = Fem->value_in_point(rp);
					sRealPoint df = Fem->partial_in_point_dx_dy(rp);
					flag->DfDx = df.x;
					flag->DfDy = df.y;	

					Flags->Add(flag);
				}

				f >> color_scale;
				f >> isolines; 

				f.CloseFile();
			}
			catch (CException &e)
			{
				ErrorHandler(e);
			}
			Marshal::FreeHGlobal((IntPtr)file_path);

			if(isolines.GetLength() > 0 && color_scale.GetLength() > 0)
			{
				oIsoLineString = gcnew String(isolines.GetBuffer(0));
				oFileColorScaleString = gcnew String(color_scale.GetBuffer(0));
			}
		}
	
	//------------------------------------------------------------------------------------------------------
		void ExportToXls(String ^iFilePath)
		{			
			try
			{
				Excel::ApplicationClass^ excelClass = gcnew Excel::ApplicationClass();
				//excelClass->Visible = true;
				Workbook^ excelBook = excelClass->Workbooks->Add(Type::Missing);		
				Worksheet^ excelSheet  = static_cast<Worksheet^>(excelClass->ActiveSheet);
				excelSheet->Name = "Flags";	
				excelSheet->Cells[1, 1] = "x"; 
				excelSheet->Cells[1, 2] = "y";
				excelSheet->Cells[1, 3] = "f";
				excelSheet->Cells[1, 4] = "DfDx";
				excelSheet->Cells[1, 5] = "DfDy";

				int i ;
				for(int i=0; i<Flags->Count; i++)
				{
					excelSheet->Cells[i+2, 1] = Flags[i]->RealX ;
					excelSheet->Cells[i+2, 2] = Flags[i]->RealY ;
					excelSheet->Cells[i+2, 3] = Flags[i]->F;
					excelSheet->Cells[i+2, 4] = Flags[i]->DfDx;
					excelSheet->Cells[i+2, 5] = Flags[i]->DfDy;					
				}				
				//excelSheet->Cells[10, 10] = "Test";
			//	excelBook->SaveAs(iFilePath,excelBook->FileFormat,Type::Missing,Type::Missing,Type::Missing,Type::Missing,
			//		Excel::XlSaveAsAccessMode::xlExclusive,Excel::XlSaveConflictResolution::xlLocalSessionChanges,Type::Missing,Type::Missing,Type::Missing,Type::Missing);
				excelBook->SaveCopyAs(iFilePath);
				excelBook->Close(false,false,Type::Missing);
				excelClass->Quit();
				
			}catch (CException &e)
			{
				ErrorHandler(e);
			}
		}
	};
}

